package com.kjs.common.tools;

import java.util.*;

/**
 * 随机数工具
 */
public class RandomCodec {
    public static long random(long max){
        Random random = new Random();
        long r = Math.abs(random.nextLong() % max);
        if (max < 0){
            return - r;
        }
        return r;
    }
    public static int random(int max){
        Random random = new Random();
        int r = Math.abs(random.nextInt() % max);
        if (max < 0){
            return -r;
        }
        return r;
    }
    public static long random(long min, long max){
        return min + random(max - min);
    }
    public static int random(int min, int max){
        return min + random(max - min);
    }

    public static long gaussian(long min, long max, long mean, float top){
        // 为区间内的每个值产生一个概率随机数，概率值最高为top
        long num = max - min + 1;
        long total = num * 100;
        List<Long> probabilities = randomArray(num, total, 1L, (long)(total * top));
        // 得到的probabilities的总和是total
        // 第一个值为mean对应值，然后按照mean的两边走的方式顺序赋值
        Random rnd = new Random();
        long r = Math.abs(rnd.nextLong()) % total;
        // 计算该r值对应的区间数字
        long amount = probabilities.get(0);
        if (r < amount){
            return mean; // 这是期望的值
        }
        long step = 1;
        for (int index = 1; index < num;){
            long g = mean - step;
            if (g >= min){
                long probability = probabilities.get(index);
                amount += probability;
                if (r < amount){
                    return g;
                }
                ++ index;
            }
            g = mean + step;
            long probability = probabilities.get(index);
            amount += probability;
            if (r < amount){
                return g;
            }
            ++ index;
            ++ step;
        }

        return -1L;
    }

    /**
     * 为total分配num个数值，最大值不能超过top，最小值1
     * @param num 数量
     * @param total 总数
     * @param upper 最高值
     * @param lower 最小值
     * @return 随机数列表
     */
    public static List<Long> randomArray(long num, long total, long lower, long upper){
        List<Long> rs = new ArrayList<>();
        if (num == 1){
            rs.add(total);
            return rs;
        }
        int i = 1;
        long max;
        Random rnd = new Random();
        while (i < num) {
            //保证即使一个红包是最大的了,后面剩下的红包,每个红包也不会小于最小值
            max = total - lower * (num - i);
            long k = (num - i) / 2;
            //保证最后两个人拿的红包不超出剩余红包
            if (num - i <= 2) {
                k = num - i;
            }
            long m0 = max;
            //最大的红包限定的平均线上下
            if (max > upper){
                max = upper;
            }else{
                max = max / k;
            }
            long r = lower;
            //保证每个红包大于最小值,又不会大于最大值
            long v = max - lower + 1;
            if (v > 0){
                r += Math.abs(rnd.nextLong()) % v;
            }

            total -= r;
            rs.add(r);
            //System.out.println("第" + i + "个人拿到" + r + "剩下" + total);
            i++;
            //最后一个人拿走剩下的红包
            if (i == num) {
                rs.add(total);
                //System.out.println("第" + i + "个人拿到" + total + "剩下0");
            }
        }
        //取数组中最大的一个值的索引
        rs.sort((o1, o2) -> (int) (o2 - o1));

        return rs;
    }
}
